import abc
from dataclasses import dataclass
from typing import Generic, TypeVar, Union

from zkl_pyutils_registries.basics import Matcher, NotMatched

AnyKey = TypeVar("AnyKey")
AnyQuery = TypeVar("AnyQuery")
AnyMatch = TypeVar("AnyMatch")


@dataclass(frozen=True)
class ComparableMatch(Generic[AnyQuery, AnyKey]):
    matcher: 'ComparableMatcher[AnyQuery,AnyKey,AnyMatch]'
    query: AnyQuery
    key: AnyKey

    def __cmp__(self, other: 'ComparableMatch'):
        assert isinstance(other, ComparableMatch)
        assert self.matcher == other.matcher
        assert self.query == other.query
        return self.matcher.compare(self.query, self.key, other.key)


class ComparableMatcher(Matcher[AnyQuery, AnyKey, AnyMatch], abc.ABC):
    def match(self, query: AnyQuery, key: AnyKey) -> ComparableMatch[AnyQuery, AnyKey]:
        if self.filter(query, key):
            return ComparableMatch(self, query, key)
        raise NotMatched

    @abc.abstractmethod
    def filter(self, query: AnyQuery, key: AnyKey) -> bool:
        pass

    @abc.abstractmethod
    def compare(self, query: AnyQuery, key0: AnyKey, key1: AnyKey) -> Union[int, float]:
        pass
